/*
 *所有关于Mds_ProductionTask类的业务代码应在此处编写
*可使用repository.调用常用方法，获取EF/Dapper等信息
*如果需要事务请使用repository.DbContextBeginTransaction
*也可使用DBServerProvider.手动获取数据库相关信息
*用户信息、权限、角色等使用UserContext.Current操作
*Mds_ProductionTaskService对增、删、改查、导入、导出、审核业务代码扩展参照ServiceFunFilter
*/
using DGZImp.Core.BaseProvider;
using DGZImp.Core.Extensions.AutofacManager;
using DGZImp.MdsProject.DomainModels;
using System.Linq;
using DGZImp.Core.Utilities;
using System.Linq.Expressions;
using DGZImp.Core.Extensions;

using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Http;
using DGZImp.MdsProject.IRepositories;
using DGZImp.Core.DbSqlSugar;
using DGZImp.MdsProject.Models;
using DGZImp.Core.Exceptions;
using DGZImp.Core.Services;
using DGZImp.MdsProject.Devices.Models;
using DGZImp.MdsProject.Devices;
using SqlSugar;
using DGZImp.BasProject.DomainModels;
using System.Threading.Tasks;
using DGZImp.MdsProject.Devices.Entities;

namespace DGZImp.MdsProject.Services
{
    public partial class Mds_ProductionTaskService
    {
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly IMds_ProductionTaskRepository _repository;//访问数据库

        public MdsInit mdsInit = AutofacContainerModule.GetService<MdsInit>();
        public Mds_LogisticTaskService logisticTask = AutofacContainerModule.GetService<Mds_LogisticTaskService>();

        [ActivatorUtilitiesConstructor]
        public Mds_ProductionTaskService(
            IMds_ProductionTaskRepository dbRepository,
            IHttpContextAccessor httpContextAccessor
            )
        : base(dbRepository)
        {
            _httpContextAccessor = httpContextAccessor;
            _repository = dbRepository;
            //多租户会用到这init代码，其他情况可以不用
            //base.Init(dbRepository);
        }

        public async Task<bool> CreateMdsProductionTask(Aps_DistributedTask item)
        {
            var DistributedTask = new Mds_ProductionTask()
            {
                GroupId = item.GroupId,
                MachineId = item.MachineId,
                WorkOrder = item.MoCode,
                TaskStatus = 0,
                PlanBeginTime = item.StartTime,
                PlanEndTime = item.EndTime,
                PlanQty = item.Qty,
                PlanWeight = item.Weight
                //BeginTime = item.StartTime,
                //EndTime = item.EndTime
            };

            _repository.DbContext.Ado.BeginTran();
            try
            {
                await Db.DoInsertAsync(DistributedTask);
                await Db.DoUpdateAsync<Aps_DistributedTask>(new { Status = 1 }, it => it.DistributedTaskId == item.DistributedTaskId);
                _repository.DbContext.Ado.CommitTran();

            }
            catch (Exception e)
            {
                _repository.SqlSugarClient.Ado.RollbackTran();
                throw new AppException("操作失败：" + e.Message);
            }

            return true;
        }
        /// <summary>
        /// 启动生产任务
        /// </summary>
        /// <param name="taskId"></param>
        /// <returns></returns>
        /// <exception cref="AppException"></exception>
        public async Task StartProductionTask(long? taskId)
        {
            var db = _repository.DbContext;
            var task = await db.Set<Mds_ProductionTask>()
                .Where(x => x.ProductionTaskId == taskId)
                .FirstAsync();
            if (task == null)
            {
                throw new AppException("未找到对应的生产任务");
            }
            if (task.TaskStatus != (int)ProductionTaskStatus.新创建)
            {
                throw new AppException("当前生产任务状态不允许启动");
            }
            var check = await db.Set<Mds_ProductionTask>()
                .Where(x => x.MachineId == task.MachineId)
                .Where(x => x.TaskStatus == (int)ProductionTaskStatus.准备中 || x.TaskStatus == (int)ProductionTaskStatus.进行中
                    || x.TaskStatus == (int)ProductionTaskStatus.完成中)
                .FirstAsync();
            if (check != null)
            {
                throw new AppException($"当前设备正在执行任务[{check.WorkOrder}]");
            }
            // TODO 此处是否需要再调用SCADA 判断设备是否处于启动状态
            //检查生产设备是是否为空闲状态
            //var prodDevice = await db.Set<Mds_RealDevice>()
            //    .Where(x => x.MachineId == task.MachineId && x.IsMasterDevice == 1)
            //    .FirstOrDefaultAsync();
            //if (prodDevice == null)
            //    throw new AppException("当前任务的生产设备未配置 数据采集 信息。");
            //var deviceInfo = mdsInit.devices.Where(x => x.Id == prodDevice.RealDeviceId.ToString()).FirstOrDefault()?.Device as Productor;
            //if (deviceInfo == null)
            //    throw new AppException($"当前设备生产设备 {prodDevice.DeviceName} 的 数据采集服务 未启动，请确认");

            //if (deviceInfo.Data.Status != ProductorStatusEmun.设备待机)
            //{
            //    await AddTaskLog(task.ProductionTaskId, LogMessageType.警告, $"当前设备 {deviceInfo.Name}/{deviceInfo.Code} 不处于 待机状态");
            //    return;
            //}
            await db.DoUpdateAsync<Mds_ProductionTask>(new
            {
                TaskStatus = (int)LogisticTaskStatus.准备中,
            }, x => x.ProductionTaskId == task.ProductionTaskId);
        }

        /// <summary>
        /// 完成生产任务
        /// </summary>
        /// <param name="taskId"></param>
        /// <param name="reason">手动完成原因</param>
        /// <param name="isManually">是否手动请求</param>
        /// <returns></returns>
        /// <exception cref="AppException"></exception>
        public async Task FinishProductionTask(long? taskId, ProductorData Data = null, string reason = null, bool isManually = false)
        {
            var db = _repository.DbContext;
            var task = await db.Set<Mds_ProductionTask>()
                .Where(x => x.ProductionTaskId == taskId)
                .FirstAsync();
            if (task == null)
                throw new AppException("未找到对应的生产任务");
            if (task.TaskStatus == (int)ProductionTaskStatus.完成中 || task.TaskStatus == (int)ProductionTaskStatus.已完成)
            {
                SysLogger.LogInformation($"当前任务{taskId} 已是完成中 或已完成，无需处理");
                return;
            }
            if (task.TaskStatus != (int)ProductionTaskStatus.进行中 && !isManually)
            {
                throw new AppException("当前生产任务状态不允许完成");
            }

            var remarks = $"{task.Remarks} \n " +
                          $"强制完成时间：{DateTime.Now}, 强制完成原因：{reason}";
            await db.DoUpdateAsync<Mds_ProductionTask>(new
            {
                TaskStatus = (int)LogisticTaskStatus.完成中,
                EndTime = DateTime.Now,
                FininsQty = Data?.FinishedQuantity ?? 0,
                Remarks = isManually ? remarks : null
            }, x => x.ProductionTaskId == task.ProductionTaskId);
        }

        public async Task FinishProductionTask(long machineId, long? taskId)
        {
            var db = _repository.DbContext;
            var devices = await db.Queryable<Mds_RealDevice>()
                .Where(x => x.MachineId == machineId).ToListAsync();
            var masterDevice = devices.Where(x => x.IsMasterDevice == 1).FirstOrDefault();
            if (masterDevice == null)
            {
                SysLogger.LogError("当前设备非生产类型，请确认");
                return;
            }
            //查询下对接
            var bottomConnector = devices.Where(x => x.IsMasterDevice == 0 &&
                x.Category == (int)RealDeviceTypeEmun.Connector_BOT).FirstOrDefault();
            if (bottomConnector != null)
            {
                var bottomDevice = mdsInit.devices.Where(x => x.Id == bottomConnector.RealDeviceId.ToString()).FirstOrDefault()?.Device as Connector;
                if (bottomDevice == null)
                {
                    await AddTaskLog(taskId, LogMessageType.错误, "当前配置了下对接，但未启动下对接设备");
                    return;
                }
                if (bottomDevice.Data.TankShipOut != ConnectorShipOutEnum.出罐)
                {
                    await AddTaskLog(taskId, LogMessageType.提示, "当前下对接设备未发出出罐信号");
                    return;
                }
            }

            await FinishProductionTask(taskId);
        }
        /// <summary>
        /// 自动检查生产任务，判断是否能启动
        /// </summary>
        public async Task AutoSendProductionTask()
        {
            var db = _repository.DbContext;
            // 获取所有准备中的任务
            var taskList = await db.Set<Mds_ProductionTask>()
                .Where(x => x.TaskStatus == (int)ProductionTaskStatus.准备中)
                .ToListAsync();
            var machineList = taskList.Select(x => x.MachineId).Distinct().ToList();
            var allRealDevices = await db.Set<Mds_RealDevice>()
                .Where(x => machineList.Contains(x.MachineId))
                .ToListAsync();
            foreach (var item in taskList)
            {
                try
                {
                    //获取执行任务所需的主生产设备
                    var realDevices = allRealDevices.Where(x => x.IsMasterDevice == 1)
                        .Where(x => x.MachineId == item.MachineId).ToList();
                    if (realDevices.Count == 0)
                        throw new AppException("未找可执行任务的主生产设备");
                    else if (realDevices.Count > 1)
                        throw new AppException("找到多个可执行任务的主生产设备，请检查");
                    var realDevice = realDevices.First();
                    if (realDevice.Category == (int)RealDeviceTypeEmun.PRD_PF)
                    {
                        //配粉

                    }
                    else if (realDevice.Category == (int)RealDeviceTypeEmun.PRD_ZF)
                    {
                        //制粉
                        //先找到对应的上对接机构，判断上对接机构是否处于抱紧状态
                        var otherDevices = allRealDevices.Where(x => x.IsMasterDevice != 1)
                            .Where(x => x.MachineId == item.MachineId).ToList();
                        var topDevices = otherDevices.Where(x => x.Category == (int)RealDeviceTypeEmun.Connector_TOP).ToList();
                        if (topDevices.Count == 0)
                            throw new AppException("未找到对应的上对接机构");
                        else if (topDevices.Count > 1)
                            throw new AppException("找到多个对应的上对接机构，请检查");
                        var topDevice = mdsInit.devices.Where(x => x.Id == topDevices[0].RealDeviceId.ToString()).FirstOrDefault()?.Device;
                        if (topDevice == null)
                            throw new AppException("未找到对应的上对接机构实例");
                        var startFlag = true;
                        //TODO 确认这里的判断信号点位是否正确
                        if (((Connector)topDevice).Data.IsFull != GoodsStatusEnum.有货)
                        {
                            await AddTaskLog(item.ProductionTaskId, LogMessageType.提示, $"材料未就绪，即将生成上料任务");
                            //生成上料任务
                            startFlag = await GenerateInLogisticTask(item);
                        }
                        //再找到对应的下对接机构，判断下对接机构是否处于抱紧状态
                        var bottomDevices = otherDevices.Where(x => x.Category == (int)RealDeviceTypeEmun.Connector_BOT).ToList();
                        if (bottomDevices.Count == 0)
                            throw new AppException("未找到对应的下对接机构");
                        else if (bottomDevices.Count > 1)
                            throw new AppException("找到多个对应的下对接机构，请检查");
                        var bottomDevice = mdsInit.devices.Where(x => x.Id == bottomDevices[0].RealDeviceId.ToString()).FirstOrDefault()?.Device;
                        if (bottomDevice == null)
                            throw new AppException("未找到对应的下对接机构实例");
                        //TODO 确认这里的判断信号点位是否正确
                        if (((Connector)bottomDevice).Data.IsFull != GoodsStatusEnum.有货)
                        {
                            await AddTaskLog(item.ProductionTaskId, LogMessageType.警告, $"空罐未就绪，等待空罐就绪后处理");
                            // 生成补空罐任务
                            startFlag = await GenerateReplenishTankTask(realDevice, item) && startFlag;
                        }
                        //TODO 其他要做的检查以及下发指令
                        //...
                        if (!startFlag) continue;
                    }
                    else if (realDevice.Category == (int)RealDeviceTypeEmun.PRD_HF)
                    {
                        //混粉
                        var procFlag = await ProcessHFProductionTask(item, realDevice);
                        if (!procFlag) continue;
                    }
                    else if (realDevice.Category == (int)RealDeviceTypeEmun.PRD_YX)
                    {
                        //压型
                        var procFlag = await ProcessYXProductiontask(item, realDevice);
                        if (!procFlag) continue;

                    }
                    else if (realDevice.Category == (int)RealDeviceTypeEmun.PRD_SJ)
                    {
                        //烧结
                        var procFlag = await ProcessSJProductionTask(item, realDevice);
                        if (!procFlag) continue;
                    }
                    else
                    {
                        throw new AppException($"任务的主生产设备类型[{realDevice.Category}]不正确，无法启动任务");
                    }
                    db.Ado.BeginTran();
                    try
                    {
                        await db.DoUpdateAsync<Mds_ProductionTask>(new
                        {
                            TaskStatus = (int)ProductionTaskStatus.进行中,
                            BeginTime = DateTime.Now
                        }, x => x.ProductionTaskId == item.ProductionTaskId);
                        await AddTaskLog(item.ProductionTaskId, LogMessageType.成功, $"生产任务已启动");
                        //if (realDevice.Category == (int)RealDeviceTypeEmun.PRD_PF)
                        //{
                        //    await db.DoUpdateAsync<Mds_ProductionTask>(new
                        //    {
                        //        TaskStatus = (int)ProductionTaskStatus.完成中,
                        //        BeginTime = DateTime.Now,
                        //    }, x => x.ProductionTaskId == item.ProductionTaskId);
                        //    await AddTaskLog(item.ProductionTaskId, LogMessageType.成功, $"当前未 对接配粉设备，自动完成配粉任务");
                        //}
                        db.Ado.CommitTran();
                    }
                    catch (Exception)
                    {
                        db.Ado.RollbackTran();
                        throw;
                    }
                }
                catch (Exception e)
                {
                    SysLogger.LogError(e, "生产任务启动异常");
                    await AddTaskLog(item.ProductionTaskId, LogMessageType.错误, $"生产任务启动失败：{e.Message}");
                    continue;
                }
            }
        }
        private async Task<bool> ProcessHFProductionTask(Mds_ProductionTask taskItem, Mds_RealDevice realDevice)
        {
            var productorHF = mdsInit.devices.Where(x => x.Id == realDevice.RealDeviceId.ToString()).FirstOrDefault()?.Device as Productor;
            if (productorHF == null)
            {
                await AddTaskLog(taskItem.ProductionTaskId, LogMessageType.错误, $"生产设备{realDevice.DeviceName}未配置或启动MCS数据采集服务，请确认");
                return false;
            }
            //判断混粉机是否空闲状态
            if (productorHF.Data == null)
            {
                SysLogger.LogError($"生产设备{realDevice.DeviceName}未能读取到SCADA系统的 数据信息，请确认");
                return false;
            }
            if (productorHF.Data.Status != ProductorStatusEmun.设备待机)
            {
                await AddTaskLog(taskItem.ProductionTaskId, LogMessageType.错误, $"生产设备{realDevice.DeviceName}状态 {productorHF.Data.Status} 不可用，请确认");
                return false;
            }
            //产生当前任务的物流调度任务
            return await GenerateInLogisticTask(taskItem);
        }

        private async Task<bool> ProcessYXProductiontask(Mds_ProductionTask taskItem, Mds_RealDevice realDevice)
        {
            //压型调度任务产生时，检查上对接对接是否有货 压型时：检查 压型上对接设备状态 以及 是否有罐
            var productorYX = mdsInit.devices.Where(x => x.Id == realDevice.RealDeviceId.ToString()).FirstOrDefault()?.Device as Productor;
            if (productorYX == null)
            {
                await AddTaskLog(taskItem.ProductionTaskId, LogMessageType.错误, $"生产设备 {realDevice.DeviceName} 未配置或启动MCS数据采集服务，请确认");
                return false;
            }
            //判断混粉机是否空闲状态
            if (productorYX.Data == null)
            {
                SysLogger.LogError($"生产设备 {realDevice.DeviceName} 未能读取到SCADA系统的 数据信息，请确认");
                return false;
            }

            // - 获取上对接设备
            var connectorTop = await Db.Set<Mds_RealDevice>()
                .Where(a => a.MachineId == realDevice.MachineId && a.Category == (int)RealDeviceTypeEmun.Connector_TOP)
                .FirstOrDefaultAsync();
            if (connectorTop == null)
            {
                await AddTaskLog(taskItem.ProductionTaskId, LogMessageType.错误, $"生产设备{realDevice.DeviceName} 无对应上对接机构，请确认");
                return false;
            }
            // - 设备信息
            var connectorTopDevice = mdsInit.devices.Where(a => a.Id == connectorTop.RealDeviceId.ToString()).FirstOrDefault();
            if (connectorTopDevice == null)
            {
                await AddTaskLog(taskItem.ProductionTaskId, LogMessageType.错误, $"生产设备{realDevice.DeviceName} 对应上对接机构数据采集未开启，请确认");
                return false;
            }
            // - 是否有货
            if (((Connector)connectorTopDevice.Device).Data.IsFull == GoodsStatusEnum.有货)
            {
                await AddTaskLog(taskItem.ProductionTaskId, LogMessageType.错误, $"生产设备{realDevice.DeviceName} 上对接机构目前有货，无法下发任务，请确认");
                return false;
            }

            //产生当前任务的物流调度任务
            return await GenerateInLogisticTask(taskItem);
        }

        private async Task<bool> ProcessSJProductionTask(Mds_ProductionTask taskItem, Mds_RealDevice realDevice)
        {
            var productorSJ = mdsInit.devices.Where(x => x.Id == realDevice.RealDeviceId.ToString()).FirstOrDefault()?.Device as Productor;
            if (productorSJ == null)
            {
                await AddTaskLog(taskItem.ProductionTaskId, LogMessageType.错误, $"生产设备{realDevice.DeviceName}未配置或启动MCS数据采集服务，请确认");
                return false;
            }
            //判断混粉机是否空闲状态
            if (productorSJ.Data == null)
            {
                SysLogger.LogError($"生产设备{realDevice.DeviceName}未能读取到SCADA系统的 数据信息，请确认");
                return false;
            }
            if (productorSJ.Data.Status != ProductorStatusEmun.设备待机)
            {
                await AddTaskLog(taskItem.ProductionTaskId, LogMessageType.错误, $"生产设备{realDevice.DeviceName}状态 {productorSJ.Data.Status} 不可用，请确认");
                return false;
            }
            //产生当前任务的物流调度任务
            return await GenerateInLogisticTask(taskItem);
        }
        /// <summary>
        /// 自动处理主任务完成
        /// </summary>
        /// <returns></returns>
        public async Task AutoCompleteProductionTask()
        {
            var db = _repository.DbContext;
            var taskList = await db.Set<Mds_ProductionTask>()
                .Where(x => x.TaskStatus == (int)ProductionTaskStatus.完成中)
                .ToListAsync();
            foreach (var item in taskList)
            {
                db.Ado.BeginTran();
                try
                {
                    // 任务完成时 产生下一序的生产任务
                    var r = await GenerateNextTask(item);
                    if (r)
                    {
                        await db.DoUpdateAsync<Mds_ProductionTask>(new
                        {
                            TaskStatus = (int)ProductionTaskStatus.已完成
                        }, x => x.ProductionTaskId == item.ProductionTaskId);
                        await AddTaskLog(item.ProductionTaskId, LogMessageType.成功, "任务已完成");
                        //依据产出更新任务的产出数
                    }
                    db.Ado.CommitTran();
                }
                catch (Exception e)
                {
                    db.Ado.RollbackTran();
                    SysLogger.LogError(e, "自动完成生产任务异常");
                }
            }
        }

        /// <summary>
        /// 任务完成时 产生下一序的生产任务
        /// </summary>
        /// <param name="task"></param>
        /// <returns></returns>
        /// <exception cref="AppException"></exception>
        private async Task<bool> GenerateNextTask(Mds_ProductionTask task)
        {
            var db = _repository.DbContext;
            if (task.WorkOrder.IsNullOrEmpty())
            {
                await AddTaskLog(task.ProductionTaskId, LogMessageType.警告, "生产任务无工单号，未自动生成下一序的生产任务");
                return true;
            }

            var mo = await db.Set<Aps_Mo>().Where(x => x.MoCode == task.WorkOrder).FirstAsync();
            if (mo == null) throw new AppException($"未找到工单[{task.WorkOrder}]信息");
            var nextMos = await db.Set<Aps_Mo>().Where(x => x.LotNo == mo.MoCode).ToListAsync();
            if (nextMos.Count == 0)
            {
                // 当前生产任务
                var curDistributedTask = await db.Set<Aps_DistributedTask>()
                    .Where(x => mo.MoCode == x.MoCode)
                    .FirstOrDefaultAsync();

                // 是否最后的工序
                if (curDistributedTask != null && await db.Set<Bas_RouteControl>().Where(a => a.RouteNameId == curDistributedTask.RouteNameId).OrderByDescending(a => a.StepSequence).Select(a => a.StepSequence).FirstOrDefaultAsync() == curDistributedTask.StepSequence)
                    return await GenerateProductionBlanking(task);

                // 不是最后的工序
                await AddTaskLog(task.ProductionTaskId, LogMessageType.警告, $"工单[{mo.MoCode}]没有下一序的工单，未自动生成下一序的生产任务");
                return false;
            }
            var productionTasks = await db.Set<Mds_ProductionTask>()
                .Where(x => SqlFunc.ContainsArray(nextMos.Select(t => t.MoCode).ToArray(), x.WorkOrder))
                .ToListAsync();

            nextMos = nextMos.Where(x => !productionTasks.Select(t => t.WorkOrder).Contains(x.MoCode)).ToList();
            if (nextMos.Count == 0)
            {
                await AddTaskLog(task.ProductionTaskId, LogMessageType.提示, $"未自动生成下一序的生产任务，因为工单下一序的生产任务都已完成");
                return true;
            }

            Mds_ProductionTask nextTask = null;

            //查找APS排程结果下一工单执行设备
            var apsRes = await db.Set<Aps_DistributedTask>()
                .Where(x => SqlFunc.ContainsArray(nextMos.Select(t => t.MoCode).ToArray(), x.MoCode))
                .OrderBy(x => x.Weight, OrderByType.Desc)
                .OrderBy(x => x.MoCode)
                .ToListAsync();
            if (apsRes.Count > 0)
            {
                nextTask = new Mds_ProductionTask()
                {
                    GroupId = apsRes.First().GroupId,
                    WorkOrder = apsRes.First().MoCode,
                    MachineId = apsRes.First().MachineId,
                    TaskStatus = (int)ProductionTaskStatus.新创建,
                    PlanBeginTime = apsRes.First().StartTime,
                    PlanEndTime = apsRes.First().EndTime,
                    PlanQty = apsRes.First().Qty,
                    PlanWeight = apsRes.First().Weight
                };
            }

            //如果没有排程结果，则根据路由配置查找下一个任务
            if (nextTask == null)
            {
                var salesOrderMat = await db.Set<Aps_SalesOrder>()
                    .Where(x => x.SalesOrderId == mo.SalesOrderId)
                    .Select(x => x.MaterialId)
                    .FirstAsync();
                //找到产品工艺
                var routeId = await db.Set<Bas_RouteUsage>()
                    .Where(x => x.Sku == salesOrderMat)
                    .Select(x => x.RouteNameId)
                    .FirstAsync();
                var routers = await db.Set<Bas_RouteControl>()
                    .LeftJoin<Bas_RouteDevice>((x, b) => x.RouteControlId == b.RouteControlId)
                    .Where(x => x.RouteNameId == routeId)
                    .OrderBy(x => x.StepSequence)
                    .Select((x, b) => new
                    {
                        x.RouteControlId,
                        x.CurrentGroupId,
                        b.MachineId,
                        x.StepSequence
                    })
                    .ToListAsync();
                //根据当前设备查找当前工序及下一个工序
                var currRouter = routers.Where(x => x.MachineId == task.MachineId).FirstOrDefault();
                if (currRouter != null)
                {
                    var nextRouter = routers.Where(x => x.StepSequence >= currRouter.StepSequence &&
                                                        x.RouteControlId != currRouter.RouteControlId
                    ).FirstOrDefault();
                    //ToDo
                    //设备状态
                    //设备已经有未完成的生产任务
                    if (nextRouter != null)
                    {
                        //找到下一工序，产生工单
                        var nextMo = nextMos.First();
                        nextTask = new Mds_ProductionTask
                        {
                            GroupId = nextRouter.CurrentGroupId,
                            WorkOrder = nextMo.MoCode,
                            MachineId = nextRouter.MachineId,
                            TaskStatus = (int)ProductionTaskStatus.新创建,
                            PlanBeginTime = DateTime.Now,
                            PlanEndTime = nextMo.DeadLine,
                        };
                    }
                }
                if (nextTask == null)
                {
                    await AddTaskLog(task.ProductionTaskId, LogMessageType.警告,
                        $"工单[{mo.MoCode}]依据工艺路线未找到下一工序工单，未自动生成下一序的生产任务。[{salesOrderMat},{routeId},{currRouter?.CurrentGroupId}]");
                    return false;
                }
            }
            if (nextTask != null)
            {
                db.Ado.BeginTran();
                try
                {
                    var ApsDistributedTaskIds = apsRes.Select(a => a.DistributedTaskId).ToList();
                    await db.DoUpdateAsync<Aps_DistributedTask>(new { Status = 1 }, x => ApsDistributedTaskIds.Contains(x.DistributedTaskId));
                    await db.DoUpdateAsync<Aps_DistributedTask>(new { Status = 2, FinishedQty = task.FinishedQty }, x => x.MoCode == task.WorkOrder);
                    await db.DoInsertAsync(nextTask);
                    await AddTaskLog(task.ProductionTaskId, LogMessageType.成功, "自动生成下一序的生产任务", nextTask.WorkOrder);
                    db.Ado.CommitTran();
                }
                catch (Exception ex)
                {
                    db.Ado.RollbackTran();
                    await AddTaskLog(task.ProductionTaskId, LogMessageType.错误, $"自动生成下一序的生产任务失败，{ex.Message}");
                    throw new AppException(ex.Message);
                }
            }
            return true;
        }

        /// <summary>
        /// 生成生产最后工序下料物流任务
        /// </summary>
        /// <param name="task"></param>
        /// <returns></returns>
        private async Task<bool> GenerateProductionBlanking(Mds_ProductionTask task)
        {
            try
            {
                ArgumentNullException.ThrowIfNull(task);
                SysLogger.LogInformation($"开始生成生产最后工序下料物流任务，生产设备Id：{task.MachineId}");

                var db = _repository.DbContext;

                // 获取当前生产设备
                var device = mdsInit.devices.FirstOrDefault(x => x.MachineId == task.MachineId && x.IsMasterDevice == 1)
                             ?? throw new NullReferenceException($"未找到Id {task.MachineId} 对应生产设备");

                // 获取设备下料点
                var beginLogistic = await db.Set<Mds_LogisticSite>()
                    .LeftJoin<Mds_LogisticSiteInout>((a, b) => a.LogisticSiteId == b.LogisticSiteId && b.IsValid == 1)
                    .Where((a, b) => a.Enabled == 1)
                    .Where((a, b) => b.MachineId == device.MachineId && b.OutFlag == 1)
                    .FirstOrDefaultAsync() ?? throw new InvalidOperationException($"生产设备 {device.Name}/{device.MachineCode} 未配置下料点");

                var targetLogistic = await db.Set<Mds_LogisticSite>()
                    .LeftJoin<Mds_LogisticSiteInout>((a, b) => a.LogisticSiteId == b.LogisticSiteId && b.IsValid == 1)
                    .Where((a, b) => a.Enabled == 1 && (a.Occupied == null || a.Occupied == 0))
                    .Where((a, b) => b.MachineId == device.MachineId && b.TankOutFlag == 1)
                    .Where((a, b) => !SqlFunc.Subqueryable<Mds_LogisticTask>()
                        .Where(c => c.EndSiteId == a.LogisticSiteId &&
                                    c.IsValid == 1 &&
                                    (c.TaskStatus == (int)LogisticTaskStatus.新创建 ||
                                     c.TaskStatus == (int)LogisticTaskStatus.准备中 ||
                                     c.TaskStatus == (int)LogisticTaskStatus.进行中)
                        ).Any())
                    .FirstOrDefaultAsync() ?? throw new InvalidOperationException($"生产设备 {device.Name}/{device.MachineCode} 未找到放料点（无空闲/未配置）");

                // 创建并下发任务
                try
                {
                    await logisticTask.AddLogisticTask(new Mds_LogisticTask
                    {
                        TaskStatus = (int)LogisticTaskStatus.新创建,
                        BeginSiteId = beginLogistic.LogisticSiteId,
                        EndSiteId = targetLogistic.LogisticSiteId,
                        WorkOrder = task.WorkOrder
                    });
                }
                catch (Exception e)
                {
                    await AddTaskLog(task?.ProductionTaskId, LogMessageType.警告, $"上料物流任务生成失败：{e.Message}");
                    return false;
                }
            }
            catch (Exception ex)
            {
                SysLogger.LogError(ex, "生成生产下料物流任务失败");
                await AddTaskLog(task?.ProductionTaskId, LogMessageType.错误, $"生成生产下料物流任务失败，错误：{ex.Message}");
                return false;
            }

            return true;
        }

        /// <summary>
        /// 生成上料物流任务
        /// </summary>
        /// <param name="task"></param>
        /// <returns></returns>
        private async Task<bool> GenerateInLogisticTask(Mds_ProductionTask task)
        {
            var db = _repository.DbContext;
            //获取当前生产任务的前一个生产任务
            var moInfo = await db.Set<Aps_DistributedTask>().Where(x => x.MoCode == task.WorkOrder).FirstAsync();
            string moLot = moInfo?.PreMoCode;
            var prevMo = await db.Set<Aps_DistributedTask>().Where(x => x.MoCode == moLot).FirstAsync();
            string prevMoCode = prevMo?.MoCode;
            var prevTask = await db.Set<Mds_ProductionTask>().Where(x => x.WorkOrder == prevMoCode).FirstAsync();
            if (prevTask == null)
            {
                await AddTaskLog(task.ProductionTaskId, LogMessageType.警告, $"上料物流任务生成失败，因为未获取到上一序的生产任务");
                return false;
            }
            //获取前一个生产任务执行设备的下料点和当前生产任务执行设备的上料点
            var prevSites = await db.Set<Mds_LogisticSiteInout>().Where(x => x.MachineId == prevTask.MachineId)
                .Where(x => x.OutFlag == 1)
                .ToListAsync();
            if (prevSites.Count == 0)
            {
                await AddTaskLog(task.ProductionTaskId, LogMessageType.警告, $"上料物流任务生成失败，未获取到上一序生产任务执行设备的下料点");
                return false;
            }
            else if (prevSites.Count > 1)
            {
                await AddTaskLog(task.ProductionTaskId, LogMessageType.警告, $"上料物流任务生成失败，上一序生产任务执行设备配置了多个下料点");
                return false;
            }
            var currSites = await db.Set<Mds_LogisticSiteInout>().Where(x => x.MachineId == task.MachineId)
                .Where(x => x.InFlag == 1)
                .ToListAsync();
            if (currSites.Count == 0)
            {
                await AddTaskLog(task.ProductionTaskId, LogMessageType.警告, $"上料物流任务生成失败，未获取到当前生产任务执行设备的上料点");
                return false;
            }
            else if (currSites.Count > 1)
            {
                await AddTaskLog(task.ProductionTaskId, LogMessageType.警告, $"上料物流任务生成失败，当前生产任务执行设备配置了多个上料点");
                return false;
            }

            // 如果设备有任务是相同起点终点，视为已生成任务，跳过下发新任务
            var beginSiteId = prevSites.First().LogisticSiteId;
            var endSiteId = currSites.First().LogisticSiteId;

            var hasTask = await Db.Set<Mds_LogisticTask>()
                .Where(a => a.TaskStatus != (int)LogisticTaskStatus.已取消 && a.TaskStatus != (int)LogisticTaskStatus.已完成)
                .Where(a => a.BeginSiteId == beginSiteId && a.EndSiteId == endSiteId)
                .AnyAsync();
            if (hasTask)
            {
                SysLogger.LogInformation($"上料物流任务已存在相同起点和终点任务，跳过生成新任务 起点Id-终点Id {beginSiteId}-{endSiteId}");
                return true;
            }

            //生成上料物流任务
            try
            {
                await logisticTask.AddLogisticTask(new Mds_LogisticTask
                {
                    BeginSiteId = beginSiteId,
                    EndSiteId = endSiteId,
                    WorkOrder = task.WorkOrder,
                });
            }
            catch (Exception e)
            {
                await AddTaskLog(task.ProductionTaskId, LogMessageType.警告, $"上料物流任务生成失败，{e.Message}");
                return false;
            }
            return true;
        }

        /// <summary>
        /// 生产'气流磨_接粉位补细粉空罐'任务
        /// </summary>
        /// <param name="deviceId"></param>
        /// <param name="taskNo"></param>
        private async Task<bool> GenerateReplenishTankTask(Mds_RealDevice? device, Mds_ProductionTask task)
        {
            if (device == null)
            {
                await AddTaskLog(task.ProductionTaskId, LogMessageType.错误, $"生成'气流磨_接粉位补细粉空罐'任务失败：未传入设备信息");
                return false;
            }
            SysLogger.LogInformation($"开始生成'气流磨_接粉位补细粉空罐'任务,设备ID {device.MachineId}");

            // 气流磨设备
            if (device.Category != (int)RealDeviceTypeEmun.PRD_ZF)
            {
                await AddTaskLog(task.ProductionTaskId, LogMessageType.错误, $"当前设备{device.DeviceName} 非气流磨设备");
                return false;
            }

            var db = _repository.DbContext;
            // 目标点：设备下料口
            const int logisticType = (int)LogisticTaskTypeEnum.气流磨_接粉位补细粉空罐;
            var logTypeInfo = await db.Set<Mds_LogisticType>()
                .Where(a => a.LogisticType == logisticType && a.Enabled == 1)
                .FirstOrDefaultAsync();

            var logisticSiteList = await db.Set<Mds_LogisticSite>()
                .LeftJoin<Mds_LogisticSiteInout>((a, b) => a.LogisticSiteId == b.LogisticSiteId && b.IsValid == 1)
                .Where((a, b) => a.Enabled == 1)
                .Where((a, b) => b.MachineId == device.MachineId)
                .Select((a, b) => b)
                .ToListAsync();
            if (logisticSiteList.Count < 1)
            {
                await AddTaskLog(task.ProductionTaskId, LogMessageType.错误, $"当前气流磨设备{device.DeviceName} 下对接无上下料点位信息配置");
                return false;
            }

            var targetLogistic = logisticSiteList.FirstOrDefault(a => a.OutFlag == 1);
            if (targetLogistic == null)
            {
                await AddTaskLog(task.ProductionTaskId, LogMessageType.警告, $"当前气流磨设备{device.DeviceName} 下对接无下料口点位信息配置");
                return false;
            }

            // - 校验是否有相同任务
            var hasTask = await db.Set<Mds_LogisticTask>()
                .Where(a => a.TaskStatus == (int)LogisticTaskStatus.新创建 || a.TaskStatus == (int)LogisticTaskStatus.准备中 ||
                            a.TaskStatus == (int)LogisticTaskStatus.进行中)
                .Where(a => a.LogisticTypeId == logTypeInfo.LogisticTypeId && a.BeginSiteId == targetLogistic.LogisticSiteId)
                .AnyAsync();

            if (hasTask)
            {
                SysLogger.LogInformation("当前点位已经下发 同类型的 物流任务");
                return true;
            }

            // 起始点：细粉管空罐线出口(定义为气流磨下对接的上料口)
            var beginLogistic = logisticSiteList.FirstOrDefault(a => a.TankInFlag == 1);
            if (beginLogistic == null)
            {
                await AddTaskLog(task.ProductionTaskId, LogMessageType.警告, $"未找到当前气流磨设备{device.DeviceName}对应‘细粉空罐线入口(气流磨下对接上料口)’配置");
                return false;
            }

            // 创建并下发空罐任务
            try
            {
                await logisticTask.AddLogisticTask(new Mds_LogisticTask
                {
                    TaskStatus = (int)LogisticTaskStatus.新创建,
                    LogisticTypeId = logTypeInfo.LogisticTypeId,
                    BeginSiteId = beginLogistic.LogisticSiteId,
                    EndSiteId = targetLogistic.LogisticSiteId,
                    WorkOrder = task.WorkOrder
                });


            }
            catch (Exception e)
            {
                await AddTaskLog(null, LogMessageType.警告, $"上料物流任务生成失败，{e.Message}");
                return false;
            }
            return true;
        }

        /// <summary>
        /// 添加任务执行日志
        /// </summary>
        /// <param name="taskId"></param>
        /// <param name="type"></param>
        /// <param name="message"></param>
        /// <param name="msg1"></param>
        /// <param name="msg2"></param>
        /// <returns></returns>
        public async Task AddTaskLog(long? taskId, LogMessageType type, string message, string msg1 = null, string msg2 = null)
        {
            var db = _repository.DbContext;
            var log = new Mds_ProductionTaskLog
            {
                ProductionTaskId = taskId,
                LogType = (int)type,
                LogContent = message,
                Msg1 = msg1,
                Msg2 = msg2,
            };
            await db.DoInsertAsync(log);
        }


    }
}
